
// <copyright file="EnumerableExtensions.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The get key delegate.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Extensions
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;

    using SubhadraSolutions.Sharp.Utils.Collections.Concurrent;
    using SubhadraSolutions.Sharp.Utils.Collections.Generic;

    #region Delegates

    /// <summary>
    /// The get key delegate.
    /// </summary>
    /// <param name="value">
    /// The value.
    /// </param>
    /// <typeparam name="TKey">
    /// </typeparam>
    /// <typeparam name="TValue">
    /// </typeparam>
    public delegate TKey GetKeyDelegate<out TKey, in TValue>(TValue value);

    #endregion Delegates

    /// <summary>
    /// The enumerable extensions.
    /// </summary>
    public static class EnumerableExtensions
    {
        #region Static Fields

        /// <summary>
        /// The cast method info.
        /// </summary>
        private static readonly MethodInfo _castMethodInfo;

        #endregion Static Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes static members of the <see cref="EnumerableExtensions"/> class.
        /// </summary>
        static EnumerableExtensions()
        {
            _castMethodInfo = typeof(Enumerable).GetMethod("Cast");
        }

        #endregion Constructors and Finalizers

        #region Public Methods and Operators

        /// <summary>
        /// The build dictionary.
        /// </summary>
        /// <param name="enumerable">
        /// The enumerable.
        /// </param>
        /// <param name="getKeyDelegate">
        /// The get key delegate.
        /// </param>
        /// <typeparam name="TKey">
        /// </typeparam>
        /// <typeparam name="TValue">
        /// </typeparam>
        /// <returns>
        /// The <see cref="Dictionary"/>.
        /// </returns>
        public static Dictionary<TKey, TValue> BuildDictionary<TKey, TValue>(IEnumerable<TValue> enumerable, GetKeyDelegate<TKey, TValue> getKeyDelegate)
        {
            var dictionary = new Dictionary<TKey, TValue>();
            foreach (TValue value in enumerable)
            {
                TKey key = getKeyDelegate(value);
                dictionary.Add(key, value);
            }

            return dictionary;
        }

        // public static IEnumerable<TT> ConvertTo<ST, TT>(this IEnumerable<ST> enumerable) where TT:class
        // {
        // return new CastedGenericEnumerable<ST, TT>(enumerable);
        // }
        // public static IEnumerable<TT> ConvertTo<TT>(this IEnumerable enumerable)
        // {
        // return new CastedEnumerable<TT>(enumerable);
        // }
        /// <summary>
        /// The cast.
        /// </summary>
        /// <param name="enumerable">
        /// The enumerable.
        /// </param>
        /// <param name="targetType">
        /// The target type.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerable"/>.
        /// </returns>
        public static IEnumerable Cast(this IEnumerable enumerable, Type targetType)
        {
            MethodInfo castedEnumerableGenericMethod = _castMethodInfo.MakeGenericMethod(targetType);
            return castedEnumerableGenericMethod.Invoke(null, new object[] { enumerable }) as IEnumerable;
        }

        /// <summary>
        /// The get keys.
        /// </summary>
        /// <param name="pairs">
        /// The pairs.
        /// </param>
        /// <typeparam name="TKey">
        /// </typeparam>
        /// <typeparam name="TValue">
        /// </typeparam>
        /// <returns>
        /// The <see cref="IEnumerable"/>.
        /// </returns>
        public static IEnumerable<TKey> GetKeys<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
        {
            return new KeyValuePairKeyEnumerable<TKey, TValue>(pairs);
        }

        /// <summary>
        /// The get valeus.
        /// </summary>
        /// <param name="pairs">
        /// The pairs.
        /// </param>
        /// <typeparam name="TKey">
        /// </typeparam>
        /// <typeparam name="TValue">
        /// </typeparam>
        /// <returns>
        /// The <see cref="IEnumerable"/>.
        /// </returns>
        public static IEnumerable<TValue> GetValeus<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
        {
            return new KeyValuePairValueEnumerable<TKey, TValue>(pairs);
        }

        /// <summary>
        /// The to counter enumerator.
        /// </summary>
        /// <param name="enumerator">
        /// The enumerator.
        /// </param>
        /// <typeparam name="T">
        /// </typeparam>
        /// <returns>
        /// The <see cref="CounterEnumeratorDecorator"/>.
        /// </returns>
        public static CounterEnumeratorDecorator<T> ToCounterEnumerator<T>(this IEnumerator<T> enumerator)
        {
            return new CounterEnumeratorDecorator<T>(enumerator);
        }

        /// <summary>
        /// The to item lock safe enumerable.
        /// </summary>
        /// <param name="enumerable">
        /// The enumerable.
        /// </param>
        /// <typeparam name="T">
        /// </typeparam>
        /// <returns>
        /// The <see cref="IEnumerable"/>.
        /// </returns>
        public static IEnumerable<T> ToItemLockSafeEnumerable<T>(this IEnumerable<T> enumerable) where T : class
        {
            return new ItemLockSafeEnumerable<T>(enumerable);
        }

        #endregion Public Methods and Operators
    }
}